Fix propagation of build script args
authorAlex Crichton <alex@alexcrichton.com>
Wed, 10 Jun 2015 02:31:47 +0000 (19:31 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Wed, 10 Jun 2015 02:31:47 +0000 (19:31 -0700)
It looks like the recent restructuring into an O(N) pass had a regression
(reported in #1695) where deps-of-deps didn't have their build script arguments
propagated upwards. This fixes the caching logic to take into account the
profile as part of the key to ensure that we traverse targets twice if
necessary.

Closes #1695

src/cargo/ops/cargo_rustc/context.rs
src/cargo/ops/cargo_rustc/custom_build.rs
src/cargo/ops/cargo_rustc/mod.rs
tests/test_cargo_compile_custom_build.rs

index 4a1284074ae05feab8f9751331292752478a7998..6429427228379607884c96b7deba882d611f95ca 100644 (file)
@@ -36,8 +36,8 @@ pub struct Context<'a, 'cfg: 'a> {
                               Fingerprint>,
     pub compiled: HashSet<(&'a PackageId, &'a Target, &'a Profile)>,
     pub build_config: BuildConfig,
-    pub build_scripts: HashMap<(&'a PackageId, Kind),
-                               Vec<(&'a PackageId, Profile)>>,
+    pub build_scripts: HashMap<(&'a PackageId, Kind, &'a Profile),
+                               Vec<&'a PackageId>>,
 
     host: Layout,
     target: Option<Layout>,
index be426396b3d02dc0ae8560fba7f7c5308f7c7108..3e3cea9fe7d56e874b26f138cc382fa135cdf1e8 100644 (file)
@@ -347,7 +347,8 @@ impl BuildOutput {
 ///
 /// The given set of targets to this function is the initial set of
 /// targets/profiles which are being built.
-pub fn build_map(cx: &mut Context, targets: &[(&Target, &Profile)]) {
+pub fn build_map<'b, 'cfg>(cx: &mut Context<'b, 'cfg>,
+                           targets: &[(&Target, &'b Profile)]) {
     let mut ret = HashMap::new();
     let pkg = cx.get_package(cx.resolve.root());
     for &(target, profile) in targets {
@@ -356,32 +357,32 @@ pub fn build_map(cx: &mut Context, targets: &[(&Target, &Profile)]) {
     }
 
     // Make the output a little more deterministic by sorting all dependencies
-    for (&(id, kind), slot) in ret.iter_mut() {
-        slot.sort_by(|&(p1, _), &(p2, _)| p1.cmp(p2));
+    for (&(id, kind, _), slot) in ret.iter_mut() {
+        slot.sort();
         slot.dedup();
         debug!("script deps: {}/{:?} => {:?}", id, kind,
-               slot.iter().map(|&(s, _)| s.to_string()).collect::<Vec<_>>());
+               slot.iter().map(|s| s.to_string()).collect::<Vec<_>>());
     }
     cx.build_scripts = ret;
 
     // Recursive function to build up the map we're constructing. This function
     // memoizes all of its return values as it goes along.
-    fn build<'a, 'b, 'cfg>(out: &'a mut HashMap<(&'b PackageId, Kind),
-                                                Vec<(&'b PackageId, Profile)>>,
+    fn build<'a, 'b, 'cfg>(out: &'a mut HashMap<(&'b PackageId, Kind, &'b Profile),
+                                                Vec<&'b PackageId>>,
                            kind: Kind,
                            pkg: &'b Package,
                            target: &Target,
-                           profile: &Profile,
+                           profile: &'b Profile,
                            cx: &Context<'b, 'cfg>)
-                           -> &'a [(&'b PackageId, Profile)] {
+                           -> &'a [&'b PackageId] {
         // If this target has crossed into "host-land" we need to change the
         // kind that we're compiling for, and otherwise just do a quick
         // pre-flight check to see if we've already calculated the set of
         // dependencies.
         let kind = if target.for_host() {Kind::Host} else {kind};
         let id = pkg.package_id();
-        if out.contains_key(&(id, kind)) {
-            return &out[&(id, kind)]
+        if out.contains_key(&(id, kind, profile)) {
+            return &out[&(id, kind, profile)]
         }
 
         // This loop is both the recursive and additive portion of this
@@ -409,13 +410,13 @@ pub fn build_map(cx: &mut Context, targets: &[(&Target, &Profile)]) {
 
             if target.linkable() && kind == dep_kind {
                 if pkg.has_custom_build() {
-                    ret.push((pkg.package_id(), profile.clone()));
+                    ret.push(pkg.package_id());
                 }
                 ret.extend(dep_scripts.iter().cloned());
             }
         }
 
-        let prev = out.entry((id, kind)).or_insert(Vec::new());
+        let prev = out.entry((id, kind, profile)).or_insert(Vec::new());
         prev.extend(ret);
         return prev
     }
index 162930be9a565f77378e60320fe3ec4c68c21644..ee8c95a1e00f917c17c8346e62578437820b1abd 100644 (file)
@@ -451,16 +451,12 @@ fn rustc(package: &Package, target: &Target, profile: &Profile,
     }
 }
 
-fn load_build_deps(cx: &Context, pkg: &Package, profile: &Profile,
-                   kind: Kind) -> Vec<PackageId> {
+fn load_build_deps(cx: &Context, pkg: &Package,
+                   profile: &Profile, kind: Kind) -> Vec<PackageId> {
     let pkg = cx.get_package(pkg.package_id());
-    let deps = match cx.build_scripts.get(&(pkg.package_id(), kind)) {
-        Some(a) => a,
-        None => return Vec::new(),
-    };
-    deps.iter().filter(|&&(_, ref dep_profile)| profile == dep_profile)
-        .map(|&(x, _)| x.clone())
-        .collect()
+    cx.build_scripts.get(&(pkg.package_id(), kind, profile)).map(|deps| {
+        deps.iter().map(|&d| d.clone()).collect::<Vec<_>>()
+    }).unwrap_or(Vec::new())
 }
 
 // For all plugin dependencies, add their -L paths (now calculated and
index 6a2996400ee6f34984c7b9c27a3c421086a1a89a..1125dd444645c8e67f2c18ea89daa551b579cdc4 100644 (file)
@@ -1300,3 +1300,59 @@ test!(cfg_override {
     assert_that(p.cargo_process("build").arg("-v"),
                 execs().with_status(0));
 });
+
+test!(flags_go_into_tests {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [project]
+            name = "foo"
+            version = "0.5.0"
+            authors = []
+
+            [dependencies]
+            b = { path = "b" }
+        "#)
+        .file("src/lib.rs", "")
+        .file("tests/foo.rs", "")
+        .file("b/Cargo.toml", r#"
+            [project]
+            name = "b"
+            version = "0.5.0"
+            authors = []
+            [dependencies]
+            a = { path = "../a" }
+        "#)
+        .file("b/src/lib.rs", "")
+        .file("a/Cargo.toml", r#"
+            [project]
+            name = "a"
+            version = "0.5.0"
+            authors = []
+            build = "build.rs"
+        "#)
+        .file("a/src/lib.rs", "")
+        .file("a/build.rs", r#"
+            fn main() {
+                println!("cargo:rustc-link-search=test");
+            }
+        "#);
+
+    assert_that(p.cargo_process("test").arg("-v").arg("--test=foo"),
+                execs().with_status(0).with_stdout(&format!("\
+{compiling} a v0.5.0 ([..]
+{running} `rustc a[..]build.rs [..]`
+{running} `[..]build-script-build[..]`
+{running} `rustc a[..]src[..]lib.rs [..] -L test[..]`
+{compiling} b v0.5.0 ([..]
+{running} `rustc b[..]src[..]lib.rs [..] -L test[..]`
+{compiling} foo v0.5.0 ([..]
+{running} `rustc src[..]lib.rs [..] -L test[..]`
+{running} `rustc tests[..]foo.rs [..] -L test[..]`
+{running} `[..]foo-[..]`
+
+running 0 tests
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
+
+", compiling = COMPILING, running = RUNNING)));
+});